import 'dart:async';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter_sound/flutter_sound.dart';
import 'package:path_provider/path_provider.dart';
import 'package:uuid/uuid.dart';

// 保持与 audio_manager.dart 完全一致的接口和数据结构
// --- 复制 PlaybackState, PlaybackStateInfo, AudioInfo ---

/// 播放状态枚举
enum PlaybackState {
  uninitialized,
  loaded,
  playing,
  paused,
  stopped,
  completed,
  error,
  buffering
}

class PlaybackStateInfo {
  final PlaybackState state;
  final AudioInfo? audioInfo;
  final String? error;
  final bool isBuffering;
  final Duration position;
  final Duration duration;

  PlaybackStateInfo({
    required this.state,
    this.audioInfo,
    this.error,
    this.isBuffering = false,
    this.position = Duration.zero,
    this.duration = Duration.zero,
  });

  PlaybackStateInfo copyWith({
    PlaybackState? state,
    AudioInfo? audioInfo,
    String? error,
    bool? isBuffering,
    Duration? position,
    Duration? duration,
  }) {
    return PlaybackStateInfo(
      state: state ?? this.state,
      audioInfo: audioInfo ?? this.audioInfo,
      error: error ?? this.error,
      isBuffering: isBuffering ?? this.isBuffering,
      position: position ?? this.position,
      duration: duration ?? this.duration,
    );
  }
}

class AudioInfo {
  final String id;
  final String title;
  final String? artist;
  final String? album;
  final Duration? duration;
  final String source;
  final bool isLocalFile;
  final String? artworkUrl;
  final Map<String, dynamic>? extras;

  AudioInfo({
    String? id,
    required this.title,
    this.artist,
    this.album,
    this.duration,
    required this.source,
    required this.isLocalFile,
    this.artworkUrl,
    this.extras,
  }) : id = id ?? const Uuid().v4();

  factory AudioInfo.fromFilePath(String filePath) {
    final filename = filePath.split('/').last.split('\\').last;
    final title = filename.contains('.')
        ? filename.substring(0, filename.lastIndexOf('.'))
        : filename;
    return AudioInfo(
      title: title,
      source: filePath,
      isLocalFile: true,
    );
  }

  factory AudioInfo.fromUrl(String url, {String? title, String? artist}) {
    final defaultTitle = url.split('/').last;
    return AudioInfo(
      title: title ?? defaultTitle,
      artist: artist,
      source: url,
      isLocalFile: false,
    );
  }

  AudioInfo copyWith({
    String? id,
    String? title,
    String? artist,
    String? album,
    Duration? duration,
    String? source,
    bool? isLocalFile,
    String? artworkUrl,
    Map<String, dynamic>? extras,
  }) {
    return AudioInfo(
      id: id ?? this.id,
      title: title ?? this.title,
      artist: artist ?? this.artist,
      album: album ?? this.album,
      duration: duration ?? this.duration,
      source: source ?? this.source,
      isLocalFile: isLocalFile ?? this.isLocalFile,
      artworkUrl: artworkUrl ?? this.artworkUrl,
      extras: extras ?? this.extras,
    );
  }

  @override
  String toString() => '[32m${artist != null ? "$artist - " : ""}$title[0m';
}

/// flutter_sound 版本的音频管理器
class AudioManagerV2 {
  static final AudioManagerV2 _instance = AudioManagerV2._internal();
  factory AudioManagerV2() => _instance;
  AudioManagerV2._internal();

  final FlutterSoundPlayer _player = FlutterSoundPlayer();
  AudioInfo? _currentAudio;
  bool _initialized = false;
  double _volume = 1.0;
  double _speed = 1.0;
  double _pitch = 1.0;

  PlaybackStateInfo _playbackState = PlaybackStateInfo(state: PlaybackState.uninitialized);
  PlaybackStateInfo get playbackState => _playbackState;

  final _playbackStateStreamController = StreamController<PlaybackStateInfo>.broadcast();
  Stream<PlaybackStateInfo> get playbackStateStream => _playbackStateStreamController.stream;

  Function(PlaybackStateInfo state)? onPlaybackStateChanged;
  Function(Duration duration)? onDurationChanged;
  Function(Duration position)? onPositionChanged;
  Function(String error)? onError;
  Function()? onCompleted;
  Function(AudioInfo audioInfo)? onAudioChanged;

  StreamSubscription? _playerSubscription;

  Future<void> init() async {
    if (_initialized) return;
    await _player.openPlayer();
    _initialized = true;
    _updatePlaybackState(state: PlaybackState.uninitialized);
  }

  Future<void> loadAudio(
    String url, {
    Map<String, String>? headers,
    String? title,
    String? artist,
    String? album,
    String? artworkUrl,
    Map<String, dynamic>? extras,
  }) async {
    if (!_initialized) await init();
    _updatePlaybackState(state: PlaybackState.loaded);
    final isLocalFile = url.startsWith('/') || url.startsWith('file://') || (Platform.isWindows && url.contains(':\\'));
    final audioInfo = isLocalFile
        ? AudioInfo.fromFilePath(url).copyWith(
            title: title,
            artist: artist,
            album: album,
            artworkUrl: artworkUrl,
            extras: extras,
          )
        : AudioInfo.fromUrl(url, title: title, artist: artist).copyWith(
            album: album,
            artworkUrl: artworkUrl,
            extras: extras,
          );
    _currentAudio = audioInfo;
    _updatePlaybackState(audioInfo: _currentAudio);
    if (onAudioChanged != null) onAudioChanged!(_currentAudio!);
  }

  Future<void> play() async {
    if (!_initialized || _currentAudio == null) return;
    await _player.startPlayer(
      fromURI: _currentAudio!.source,
      codec: _detectCodec(_currentAudio!.source),
      whenFinished: () {
        _updatePlaybackState(state: PlaybackState.completed);
        if (onCompleted != null) onCompleted!();
      },
      // volume: _volume,
      // playbackRate: _speed,
      // flutter_sound 9.6.0 暂不支持 pitch 直接设置
    );
    _listenToPlayer();
    _updatePlaybackState(state: PlaybackState.playing);
  }

  Future<void> pause() async {
    if (!_initialized) return;
    await _player.pausePlayer();
    _updatePlaybackState(state: PlaybackState.paused);
  }

  Future<void> stop() async {
    if (!_initialized) return;
    await _player.stopPlayer();
    _updatePlaybackState(state: PlaybackState.stopped, position: Duration.zero);
  }

  Future<void> seek(Duration position) async {
    if (!_initialized) return;
    await _player.seekToPlayer(position);
  }

  Future<void> setVolume(double volume) async {
    if (!_initialized) return;
    _volume = volume.clamp(0.0, 1.0);
    await _player.setVolume(_volume);
  }

  Future<void> setSpeed(double speed) async {
    if (!_initialized) return;
    _speed = speed.clamp(0.5, 2.0);
    await _player.setSpeed(_speed);
  }

  Future<void> setPitch(double pitch) async {
    // flutter_sound 9.6.0 暂不支持 pitch 直接设置，保留接口
    _pitch = pitch;
  }

  Future<void> togglePlay() async {
    if (!_initialized) await init();
    if (_player.isPlaying) {
      await pause();
    } else {
      await play();
    }
  }

  Future<void> playAudio(
    String url, {
    Map<String, String>? headers,
    String? title,
    String? artist,
    String? album,
    String? artworkUrl,
    Map<String, dynamic>? extras,
    Function(Duration duration)? onDuration,
    Function(Duration position)? onPosition,
    Function(String error)? onPlayError,
    Function()? onComplete,
    Function(AudioInfo audioInfo)? onAudioLoaded,
  }) async {
    this.onDurationChanged = onDuration;
    this.onPositionChanged = onPosition;
    this.onError = onPlayError;
    this.onCompleted = onComplete;
    this.onAudioChanged = onAudioLoaded;
    await loadAudio(
      url,
      headers: headers,
      title: title,
      artist: artist,
      album: album,
      artworkUrl: artworkUrl,
      extras: extras,
    );
    await play();
    if (onAudioLoaded != null && _currentAudio != null) {
      onAudioLoaded(_currentAudio!);
    }
  }

  AudioInfo? getCurrentAudio() => _currentAudio;

  void _listenToPlayer() {
    _playerSubscription?.cancel();
    _playerSubscription = _player.onProgress!.listen((event) {
      final pos = event.position;
      final dur = event.duration ?? Duration.zero;
      _updatePlaybackState(position: pos, duration: dur);
      if (onPositionChanged != null) onPositionChanged!(pos);
      if (onDurationChanged != null) onDurationChanged!(dur);
    }, onError: (e) {
      _updatePlaybackState(state: PlaybackState.error, error: e.toString());
      if (onError != null) onError!(e.toString());
    });
  }

  void _updatePlaybackState({
    PlaybackState? state,
    AudioInfo? audioInfo,
    String? error,
    bool? isBuffering,
    Duration? position,
    Duration? duration,
  }) {
    _playbackState = _playbackState.copyWith(
      state: state ?? _playbackState.state,
      audioInfo: audioInfo ?? _playbackState.audioInfo,
      error: error ?? _playbackState.error,
      isBuffering: isBuffering ?? _playbackState.isBuffering,
      position: position ?? _playbackState.position,
      duration: duration ?? _playbackState.duration,
    );
    _playbackStateStreamController.add(_playbackState);
    if (onPlaybackStateChanged != null) {
      onPlaybackStateChanged!(_playbackState);
    }
  }

  Future<void> reset() async {
    if (!_initialized) return;
    await stop();
    await setVolume(1.0);
    await setSpeed(1.0);
    await setPitch(1.0);
    _currentAudio = null;
    _updatePlaybackState(
      state: PlaybackState.uninitialized,
      audioInfo: null,
      error: null,
      position: Duration.zero,
      duration: Duration.zero,
    );
    onDurationChanged = null;
    onPositionChanged = null;
    onError = null;
    onCompleted = null;
    onAudioChanged = null;
    onPlaybackStateChanged = null;
  }

  Future<void> dispose() async {
    if (!_initialized) return;
    await stop();
    // await _player.closePlayer();
    _playerSubscription?.cancel();
    _playbackStateStreamController.close();
    _currentAudio = null;
    onDurationChanged = null;
    onPositionChanged = null;
    onError = null;
    onCompleted = null;
    onAudioChanged = null;
    onPlaybackStateChanged = null;
    _initialized = false;
  }

  Codec _detectCodec(String path) {
    final ext = path.toLowerCase().split('.').last;
    switch (ext) {
      case 'mp3':
        return Codec.mp3;
      case 'aac':
        return Codec.aacADTS;
      case 'wav':
        return Codec.pcm16WAV;
      case 'm4a':
        return Codec.aacMP4;
      case 'flac':
        return Codec.flac;
      default:
        return Codec.mp3;
    }
  }
} 